import { MessageService } from './message.service';
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { tap, catchError } from 'rxjs/operators';
import { Hero, HEROES } from 'src/app/page/hero/hero';
import { HttpClient, HttpHeaders } from '@angular/common/http';
const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
@Injectable({
  providedIn: 'root'
})
export class HeroService {
  private heroesUrl = 'api/heroes'; // URL to web api

  constructor(
    private messageService: MessageService,
    private httpClient: HttpClient
  ) {}
  getHeroes(): Observable<Hero[]> {
    // 在获取到英雄数组时发送一条消息。
    this.messageService.add('HeroService:fetched heroes....');
    // of(HEROES) 会返回一个 Observable<Hero[]>，它会发出单个值，这个值就是这些模拟英雄的数组
    // 使用of()方法模拟方法一个英雄数组的数据
    return of(HEROES);
  }

  getHero(id: number): Observable<Hero> {
    this.messageService.add(`HeroService: fetched hero id=${id}`);
    console.log(this.messageService.messages.length + '');
    return of(HEROES.find(hero => hero.id === id));
  }
  getHeroesForHttp(): Observable<Hero[]> {
    //HttpClient.get 默认情况下把响应体当做无类型的 JSON 对象进行返回。 如果指定了可选的模板类型 <Hero[]>，就会给返回你一个类型化的对象。
    //RxJS 的 tap可查看 Observable 中的值，使用那些值做一些事情，并且把它们传出来。 这种 tap 回调不会改变这些值本身。
    return this.httpClient.get<Hero[]>(this.heroesUrl).pipe(
      tap(heroes => this.log('fetched heroes')),
      catchError(this.handleError('getHeroes', []))
    );
  }
  getHeroForHttp(id: number): Observable<Hero> {
    const url = `${this.heroesUrl}/${id}`;
    return this.httpClient.get<Hero>(url).pipe(
      tap(_ => this.log(`fetched hero id=${id}`)),
      catchError(this.handleError<Hero>(`getHero id=${id}`))
    );
  }

  //新增hero信息
  addHero(hero: Hero): Observable<Hero> {
    return this.httpClient
      .post<Hero>(this.heroesUrl, hero, httpOptions)
      .pipe(tap((hero: Hero) => this.log('add hero w/ id=' + hero.id)));
  }
  //删除hero：联合类型表示一个值可以是几种类型之一。 我们用竖线（ |）分隔每个类型
  deleteHero(hero: Hero | number): Observable<Hero> {
    //typeof类型保护*只有两种形式能被识别： typeof v === "typename"和 typeof v !== "typename"，
    const id = typeof hero === 'number' ? hero : hero.id;
    const url = `${this.heroesUrl}/${id}`;
    return this.httpClient.delete<Hero>(url, httpOptions).pipe(
      tap(_ => this.log(`deleted hero id=${id}`)),
      catchError(this.handleError<Hero>('deleteHero'))
    );
  }
  //搜索
  searchHeroes(terms: string): Observable<Hero[]> {
    if (!terms.trim()) {
      return of([]);
    }
    const url=this.heroesUrl+'/?name='+terms;
    return this.httpClient
      .get<Hero[]>(url)
      .pipe(
        tap(_ => this.log(`found heroes matching "${terms}"`)),
        catchError(this.handleError<Hero[]>('searchHeroes', []))
      );
  }
  //修改
  updateHero (hero: Hero): Observable<any> {
    return this.httpClient.put(this.heroesUrl, hero, httpOptions).pipe(
      tap(_ => this.log(`updated hero id=${hero.id}`)),
      catchError(this.handleError<any>('updateHero'))
    );
  }
  private log(message: string) {
    this.messageService.add(`HeroService: ${message}`);
  }
  //错误处理
  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
      console.error(error); // log to console instead
      // TODO: better job of transforming error for user consumption
      this.log(`${operation} failed: ${error.message}`);
      // Let the app keep running by returning an empty result.
      return of(result as T);
    };
  }
}
